import React, {DependencyList, ReactNode, useCallback, useMemo} from 'react';
import {ListOperate} from "@/hooks/useList";
import {DeleteOperate} from "@/hooks/useDelete";
import ProTable, {ProColumns} from "@ant-design/pro-table";
import {Button} from "antd";
import {ProTableProps} from "@ant-design/pro-table/lib/Table";
import {RequestData, UseFetchDataAction} from "@ant-design/pro-table/lib/useFetchData";
import omit from 'omit.js';
import config from "@/config";
import {DetailsDialogProps, DialogOperate, EditDialogProps} from "@/global";

/**
 * 操作列位置
 */
export enum OptionColumnPosition {
  Left = 1,
  Right,
}

/** 表格组件 操作选项 */
export interface ProTableCrudOperate<T> {
  /** 是否显示新建按钮 */
  showCreate?: boolean;
  /** 是否显示修改按钮 */
  showEdit?: boolean;
  /** 是否显示删除按钮 */
  showDelete?: boolean;
  /** 是否显示查看按钮 */
  showDetails?: boolean;
  /** 是否显示导出按钮 */
  showExport?: boolean;
  /** 是否显示操作列 */
  showOptionColumn?: boolean;
  /** 是否显示工具栏 */
  showToolbar?: boolean;
  /** 操作列配置选项 */
  optionColumn?: ProColumns<T>;
  /** 操作列宽度 */
  optionColumnWidth?: number;
  /** 操作列标题 */
  optionColumnTitle?: string;
  /** 操作列位置 */
  optionColumnPosition?: OptionColumnPosition;
  /** 新建按钮文本 */
  createComandText?: string;
  /** 编辑按钮文本 */
  editComandText?: string;
  /** 删除按钮文本 */
  deleteComandText?: string;
  /** 查看按钮文本 */
  detailsComandText?: string;
  /** 导出按钮文本 */
  exportComandText?: string;

  /** 表格列集合 */
  cols: ProColumns<T>[];
  /** 列表操作 */
  listOperate: ListOperate<T>;
  /** 删除操作 */
  deleteOperate?: DeleteOperate<T>;
  /** 编辑操作 */
  editOperate?: DialogOperate;
  /** 详情操作 */
  detailsOperate?: DialogOperate;
  /** 获取操作列按钮集合 */
  getColumnComandItems?: (text: ReactNode, record: T, index: number, action: UseFetchDataAction<RequestData<T>>)
    => (ReactNode | string)[];

  /** 获取工具栏按钮集合 */
  getToolbarItems?: (action: UseFetchDataAction<RequestData<T>>, rows: {
    selectedRowKeys?: (string | number)[];
    selectedRows?: T[];
  }) => (ReactNode | string)[];

  /** 获取编辑组件 */
  getEditElement?: (editProps: EditDialogProps) => ReactNode;
  /** 获取详情查看组件 */
  getDetailsElement?: (detailsProps: DetailsDialogProps) => ReactNode;
}

/** 增删改查表格组件 属性 */
export interface ProTableCrudProps<T> extends ProTableProps<T, {}> {
  /** 操作选项 */
  operate: ProTableCrudOperate<T>,
  deps?: DependencyList;
}

/** 增删改查表格组件 */
function ProTableCrud<T>(props: ProTableCrudProps<T>) {
  const {rowKey = 'id'} = props;
  const operate = props.operate;
  const deps = props.deps || [];
  operate.showCreate = operate.showCreate === undefined ? true : operate.showCreate;
  operate.showEdit = operate.showEdit === undefined ? true : operate.showEdit;
  operate.showDelete = operate.showDelete === undefined ? true : operate.showDelete;
  operate.showDetails = operate.showDetails === undefined ? true : operate.showDetails;
  operate.showExport = operate.showExport === undefined ? true : operate.showExport;
  operate.showOptionColumn = operate.showOptionColumn === undefined ? true : operate.showOptionColumn;
  operate.showToolbar = operate.showToolbar === undefined ? true : operate.showToolbar;

  operate.optionColumnWidth = operate.optionColumnWidth || 120;
  operate.optionColumnTitle = operate.optionColumnTitle || '操作';
  operate.optionColumnPosition = operate.optionColumnPosition || OptionColumnPosition.Right;
  operate.createComandText = operate.createComandText || '新建';
  operate.editComandText = operate.editComandText || '修改';
  operate.deleteComandText = operate.deleteComandText || '删除';
  operate.detailsComandText = operate.detailsComandText || '查看';
  operate.exportComandText = operate.exportComandText || '导出';

  //region List
  const {sorter, tableProps, handleExport} = operate.listOperate;
  //endregion
  //region Delete
  let handleDeleteConfirm: (selectedRowKeys: string[], selectedRows: T[]) => void;
  if (operate.deleteOperate) {
    handleDeleteConfirm = operate.deleteOperate.handleDeleteConfirm;
  }
  //endregion

  //region 表格列

  /** 获取表格列 */
  const getColumns = useMemo((): (ProColumns<T>[]) => {
    let cols: ProColumns<T>[] = [];
    if (operate.cols) {
      cols = operate.cols;
    }

    //如果不显示操作类直接返回
    if (operate.showOptionColumn === false) return cols;

    //构建默认的操作列
    let opColumn: ProColumns<T> = {
      title: operate.optionColumnTitle,
      width: operate.optionColumnWidth,
      dataIndex: 'option',
      valueType: 'option',
      align: 'center',
      fixed: 'right',
    };
    //如果指定了操作列配置选项,则合并到默认的操作列
    if (operate.optionColumn) {
      opColumn = {...opColumn, ...operate.optionColumn};
    }

    //如果没有指定操作的按钮项集合,则构造默认的操作按钮
    if (!opColumn.render) {
      let colComands: (text: ReactNode, record: T, index: number, action: UseFetchDataAction<RequestData<T>>) => React.ReactNode[];
      colComands = (t, r, i, a) => {
        let sz: (ReactNode | string)[] = [];
        if (operate.getColumnComandItems) {
          sz = operate.getColumnComandItems(t, r, i, a);
        } else {
          sz.push('details');
          sz.push('edit');
          sz.push('delete');
        }
        return sz.map(p => {
          if (typeof p === 'string') {
            if (p === 'details' && operate.showDetails === true) {
              return (
                <a key="colCmdDetails" onClick={() => operate.detailsOperate && operate.detailsOperate.show({id: r[String(rowKey)]})}
                >{operate.detailsComandText}</a>
              );
            } else if (p === 'edit' && operate.showEdit === true) {
              return (
                <a key="colCmdEdit" onClick={() => operate.editOperate && operate.editOperate.show({
                  created: false,
                  id: r[String(rowKey)],
                  onSubmitSucess: operate.listOperate.handleReload
                })}
                >{operate.editComandText}</a>
              );
            } else if (p === 'delete' && operate.showDelete === true) {
              return (
                <a key="colCmdDelete"
                   onClick={() => handleDeleteConfirm && handleDeleteConfirm([r[String(rowKey)]], [r])}
                >{operate.deleteComandText}</a>
              );
            }
            return (<></>);
          } else {
            return p as ReactNode;
          }
        });
      };
      opColumn.render = colComands;
    }

    if (operate.optionColumnPosition === OptionColumnPosition.Left) {
      opColumn.fixed = 'left';
      cols.unshift(opColumn);
    } else if (operate.optionColumnPosition === OptionColumnPosition.Right) {
      cols.push(opColumn);
    }
    return cols;
  }, deps);

  //endregion

  //region 工具栏 */

  /** 获取工具栏 */
  const getToolbar = useCallback((action: UseFetchDataAction<RequestData<T>>, rows: {
    selectedRowKeys?: string[];
    selectedRows?: T[];
  }) => {
    // if (operate.showToolbar !== true) return [];

    let sz: (ReactNode | string)[] = [];
    //如果没有指定工具栏按钮,则添加默认的按钮
    if (operate.getToolbarItems) {
      sz = operate.getToolbarItems(action, rows);
    } else {
      sz.push('create');
      sz.push('edit');
      sz.push('delete');
      sz.push('export');
    }
    //数组支持字符串和ReactNode对象,如果是字符串只支持:create/edit/delete/export
    //这些字符串代表了内置的集中命令按钮,使用者可以传入内置字符和ReactNode对象来控制显示内容和顺序
    return sz.map(p => {
      if (typeof p === 'string') {
        if (p === 'create' && operate.showCreate === true) {
          return (
            <Button key="toolbarCreate" type='primary' onClick={() => operate.editOperate && operate.editOperate.show({
              created: true,
              onSubmitSucess: operate.listOperate.handleReload
            })}>
              <i className='fal fa-plus'/> {operate.createComandText}
            </Button>
          );
        } else if (p === 'edit' && operate.showEdit === true) {
          return (
            <Button
              key="toolbarEdit"
              disabled={!rows.selectedRowKeys || rows.selectedRowKeys.length !== 1}
              // @ts-ignore
              onClick={() => handleEdit && handleEdit(rows.selectedRows[0])}
            >
              <i className='icon-pencil'/> {operate.editComandText}
            </Button>
          );
        } else if (p === 'delete' && operate.showDelete === true) {
          return (
            <Button danger key="toolbarDelete" type="primary"
                    disabled={!rows.selectedRowKeys || rows.selectedRowKeys.length == 0}
                    onClick={() => handleDeleteConfirm && handleDeleteConfirm(rows.selectedRowKeys || [], rows.selectedRows || [])}
            >
              <i className="fal fa-trash-alt"/> {operate.deleteComandText}
            </Button>
          );
        } else if (p === 'export' && operate.showExport === true) {
          return (
            <Button key="toolbarExport" onClick={handleExport} disabled={action.total == 0}>
              <i className="fal fa-file-export"/> {operate.exportComandText}
            </Button>
          );
        }
        return (<></>);
      } else {
        return p as ReactNode;
      }
    });
  }, deps);

  //endregion


  /** 构建ProTable组件 */
  const tabDeps = props.deps || [];
  const tabParams = Array<any>();
  if (props.params) {
    Object.entries(props.params).map(p => {
      if ((p[1])) {
        tabParams.push(p[1]);
      }
    })
  }

  const proTable = useMemo(function () {
    //组件属性中,排查operate以外的其他属性都添加到ProTable组件中
    const ps = omit(props, ['operate', 'deps']);

    if (ps.pagination !== false) {
      if (!ps.pagination) ps.pagination = {}
      if (!ps.pagination.defaultPageSize) ps.pagination.defaultPageSize = config.defaultPageSize;
    }

    if (!ps.params) ps.params = {}
    if (!ps.params.sorter) ps.params.sorter = sorter;

    return (
      <ProTable<T>
        columns={getColumns}
        //params={{sorter}}
        // @ts-ignore
        toolBarRender={operate.showToolbar === true && getToolbar}
        {...tableProps}
        {...ps}
      />
    );
  }, [...tabDeps, sorter, ...tabParams]);

  return (
    <>
      {proTable}
      {
        // @ts-ignore
       operate.editOperate?.visible && operate.getEditElement && operate.getEditElement(operate.editOperate)}
      {
        // @ts-ignore
        operate.getDetailsElement && operate.getDetailsElement(operate.detailsOperate)}
    </>
  );
}

export default ProTableCrud;

